extern crate draw;
use draw::*;

use crate::complex::*;

/// 绘图模式 trait
pub trait CompMode {
    fn comp(&self, _: Complex) -> DrawResult;
}

pub enum DrawResult {
    Success,
    Fail,
    A,
    B,
    C,
}

pub struct App {
    /// 宽度
    w: u32,
    /// 高度
    h: u32,
    /// 精度
    a: u32,

    x: f32,
    y: f32,

    c: Option<Canvas>,
}

impl App {
    pub fn new() -> Self {
        Self {
            w: 0,
            h: 0,
            a: 0,
            x: 0.0,
            y: 0.0,
            c: None,
        }
    }

    pub fn size(mut self, w: u32, h: u32) -> Self {
        self.w = w;
        self.h = h;
        self
    }

    pub fn move_x(mut self, x: f32) -> Self {
        self.x = x;
        self
    }

    pub fn move_y(mut self, y: f32) -> Self {
        self.y = y;
        self
    }

    pub fn accuracy(mut self, a: u32) -> Self {
        self.a = a;
        self
    }

    pub fn use_mode(mut self, mode: impl CompMode) -> Self {
        self.c = Some(Canvas::new(self.w, self.h));

        for x in 0..self.w {
            for y in 0..self.h {
                let input = comp!(
                    (x as f32 - 0.5 * self.w as f32) / self.a as f32 - self.x,
                    (y as f32 - 0.5 * self.h as f32) / self.a as f32 - self.y
                );

                let elem = match mode.comp(input) {
                    DrawResult::Success => Some(
                        Drawing::new()
                            .with_shape(Shape::Circle { radius: 1 })
                            .with_xy(x as f32, y as f32)
                            .with_style(Style::stroked(1, Color::black())),
                    ),
                    DrawResult::Fail => None,
                    _ => None,
                };

                match (elem, self.c.as_mut()) {
                    (Some(e), Some(c)) => {
                        c.display_list.add(e);
                    }
                    _ => {}
                }
            }
        }

        self
    }

    pub fn save_file(&self, path: &str) {
        if let Some(c) = &self.c {
            render::save(&c, path, SvgRenderer::new()).expect("文件保存失败");
        }
    }
}
